﻿using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using System.Web.Configuration;
using System.Web.Routing;

namespace BMap
{
    internal static class JavascriptRenderer
    {
        public static void FuncBegin(this TextWriter writer)
        {
            writer.Write("<script>\r\n");
            writer.Write("    $(function () {\r\n");
        }

        public static void InitMap(this TextWriter writer, string mapId, double latitude, double longitude, int zoom)
        {
            var clientId = BaiduExtension.GetFixedMapId(mapId);
            writer.Write("        window.Map_{0}= new BMap.Map('{1}');\r\n", clientId, mapId);
            writer.Write("        window.Map_{0}.centerAndZoom(new BMap.Point({1}, {2}), {3});\r\n", clientId, latitude, longitude, zoom);
        }

        public static void FuncEnd(this TextWriter writer)
        {
            writer.Write("    });\r\n</script>");
        }

        public static void RenderJsInclude(this TextWriter writer, string mapId)
        {
            var ver = WebConfigurationManager.AppSettings["BaiduMap.Version"];
            double version;
            if (!double.TryParse(ver, out version))
            {
                version = 2.0;
            }
            var ak = WebConfigurationManager.AppSettings["BaiduMap.AK"];
            var jsUrl = string.Format("http://api.map.baidu.com/api?v={0}&ak={1}", version, ak);
            if (HttpContext.Current.Items["BMap_JS"] == null)
            {
                writer.Write("<script src=\"{0}\"></script>\r\n", jsUrl);
                HttpContext.Current.Items["BMap_JS"] = new object();
            }
        }

        private static string RenderMarker(string mapId, int index, MapMarker marker)
        {
            if (marker == null)
            {
                return null;
            }
            var markerName = string.Format("{0}_marker{1}", mapId, index);
            var builder = new StringBuilder();
            builder.AppendFormat("        var {0} = new BMap.Marker(", markerName);
            builder.AppendFormat("new BMap.Point({0}, {1})",marker.Latitude, marker.Longitude);
            if (!string.IsNullOrEmpty(marker.IconUrl))
            {
                builder.AppendFormat(",{{icon:new BMap.Icon(\"{0}\",new BMap.Size({1},{2}))}}", marker.IconUrl, marker.IconWidth, marker.IconHeight);
            }
            builder.Append(");\r\n");
            builder.AppendFormat("        window.Map_{0}.addOverlay({1});\r\n", mapId, markerName);
            builder.AppendFormat("        window.Map_{0}.markers.push({1});\r\n", mapId, markerName);
            if (marker.Draggable)
            {
                builder.AppendFormat("        {0}.enableDragging();\r\n", markerName);
            }
            if (!string.IsNullOrEmpty(marker.Animation))
            {
                builder.AppendFormat("        {0}.setAnimation({1});\r\n", markerName, marker.Animation);
            }
            if (!string.IsNullOrEmpty(marker.OnClientClick))
            {
                builder.AppendFormat("        {0}.addEventListener(\"click\",function(){{\r\n            if(typeof {1} ===\"function\"){{{1}({0});}}\r\n        }});\r\n", markerName, marker.OnClientClick);
            }
            return builder.ToString();
        }

        public static void RenderMapMarker(this TextWriter writer, string mapId, IEnumerable<MapMarker> markers)
        {
            if (markers == null || !markers.Any())
            {
                return;
            }
            mapId = BaiduExtension.GetFixedMapId(mapId);
            writer.Write("        window.Map_{0}.markers= window.Map_{0}.markers || [];\r\n", mapId);
            var mapMarkers = markers as MapMarker[] ?? markers.ToArray();
            for (int i = 0; i < mapMarkers.Length; i++)
            {
                writer.Write(RenderMarker(mapId, i, mapMarkers[i]));
            }
        }

        private static string RenderOption(MapControlOption opt)
        {
            if (opt == null)
            {
                return null;
            }
            if (opt.X == 0 && opt.Y == 0 && string.IsNullOrEmpty(opt.Type) && opt.Anchor == MapAnchorEnum.None)
            {
                return null;
            }
            var builder = new StringBuilder();
            builder.Append("{");
            if (opt.X != 0 || opt.Y != 0)
            {
                builder.AppendFormat("offset:new BMap.Size({0}, {1}),", opt.X, opt.Y);
            }
            if (!string.IsNullOrEmpty(opt.Type))
            {
                builder.AppendFormat("type:{0},", opt.Type);
            }
            if (opt.Anchor != MapAnchorEnum.None)
            {
                builder.AppendFormat("anchor:{0},", opt.Anchor);
            }
            var str = builder.ToString().TrimEnd(',');
            return str + "}";
        }

        public static void RenderMapControl(this TextWriter writer, string mapId, IEnumerable<MapControl> ctrls)
        {
            if (ctrls == null || !ctrls.Any())
                return;
            mapId = BaiduExtension.GetFixedMapId(mapId);
            foreach (var ctrl in ctrls)
            {
                writer.Write("        window.Map_{0}.addControl(\r\n", mapId);
                writer.Write("            new BMap.{0}(", ctrl.ControlType);
                writer.Write(RenderOption(ctrl.Option));
                writer.Write(")\r\n        );\r\n");
            }
        }

        public static void RenderMapLabel(this TextWriter writer, string mapId, MapLabelOption option)
        {
            if (option == null || string.IsNullOrEmpty(option.Text))
                return;
            mapId = BaiduExtension.GetFixedMapId(mapId);
            const string js = @"
        var opts = {{
            position : new BMap.Point({0},{1}),
            offset   : new BMap.Size({2}, {3})
        }};
        var label = new BMap.Label(""{4}"", opts);";
            writer.Write(js, option.PointX, option.PointY, option.OffsetX, option.OffsetY, option.Text.Replace("\"", "\\\""));
            writer.Write("\r\n");
            if (option.Style != null)
            {
                var codeBuilder = new StringBuilder();
                foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(option.Style))
                {
                    var value = property.GetValue(option.Style);
                    if (value != null)
                        codeBuilder.AppendFormat("{0}:\"{1}\",", property.Name, value.ToString().Replace("\"", "\\\""));
                }
                writer.Write("        label.setStyle({{{0}}});\r\n", codeBuilder.ToString().TrimEnd(','));
            }
            writer.Write("        window.Map_{0}.addOverlay(label);\r\n", mapId);
        }
    }
}
